<?PHP
  class Settings{

    protected $area              = "global";
    protected $areaType          = "global";
    protected $dir               = "global";
    protected $parent            = null;
    protected $properties        = array();
    protected static $instances  = array();
    protected static $default    = null;
    protected static $root       = null;

    public function get($property, $role = null, $allowCache = true){
      $res = null;
      if(!$role){
        $role = $_SESSION['user']->role->ID;
      }
      if(isset($this->properties[$property]) && $allowCache){
        $res = $this->properties[$property];
      }
      else{
        $res = $this->getFromDB($property, $role);
        if(!$res && $this->parent != null){
          $res = $this->parent->get($property,$role, $allowCache);
        }
        if($allowCache){
          $this->properties[$property] = $res;
        }
      }
      return $res;
    }

    protected function getFromDB($property, $role){
      $area     = $GLOBALS['db']->EscapeString($this->area);
      $areaType = $GLOBALS['db']->EscapeString($this->areaType);
      $dir      = $GLOBALS['db']->EscapeString($this->dir);
      $property = $GLOBALS['db']->EscapeString($property);
      $sql      = "";
      if(isset($_SESSION['user'])){
       $sql = "SELECT value FROM {'dbprefix'}settings WHERE role = '".$role."' AND area = '".$area."' AND areaType = '".$areaType."' AND dir = '".$dir."' AND property = '".$property."' UNION ";
      }
      $sql .= "SELECT value FROM {'dbprefix'}settings WHERE role = '3' AND area = '".$area."' AND areaType = '".$areaType."' AND dir = '".$dir."' AND property = '".$property."'";
      return $GLOBALS['db']->ReadField($sql);
    }

    public function set($property,$value,$role){
      $valueChanged = $this->get($property) != $value;
      $area     = $GLOBALS['db']->EscapeString($this->area);
      $areaType = $GLOBALS['db']->EscapeString($this->areaType);
      $property = $GLOBALS['db']->EscapeString($property);
      $value    = $GLOBALS['db']->EscapeString($value);
      $role     = $GLOBALS['db']->EscapeString($role);
      $dir      = $GLOBALS['db']->EscapeString($this->dir);
      $valueChanged = $valueChanged || ($dir == "global" && $area == "global" && $areaType == "global" && $role == "3");
      $allUserData = $GLOBALS['db']->ReadRow("SELECT * FROM  {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."'", false);
      if($valueChanged){
        $exists = $GLOBALS['db']->ReadField("SELECT COUNT(*) FROM {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."' AND dir = '".$dir."'") > 0;
        if($exists){
          $res = $GLOBALS['db']->Execute("UPDATE {'dbprefix'}settings SET value = '".$value."' WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."' AND dir = '".$dir."'");
         }
        else{
          $res = $GLOBALS['db']->Execute("INSERT INTO {'dbprefix'}settings (value,area,areaType,property,role,description,type,dir) VALUES ('".$value."', '".$area."', '".$areaType."', '".$property."', '".$role."','".$allUserData->description."','".$allUserData->type."','".$dir."')");
        }
      }
      else{
        $GLOBALS['db']->Execute("DELETE FROM {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."' AND dir = '".$dir."'");
      }
      Cache::clear();
      return $res;
    }

    protected function setArea($area){
      $this->area = $area;
    }

    protected function setAreaType($area){
      $this->areaType = $area;
    }

    protected function setDir($dir){
      $this->dir = $dir;
    }

    public static function getInstance(){
      if(!isset(self::$default)){
        if(!isset(self::$instances["global"]["global"]["global"])){
            $res = new Settings();
            self::$instances["global"]["global"]["global"] = $res;
        }
        else{
          $res = self::$instances["global"]["global"]["global"];
        }
        self::$root = $res;
      }
      else{
        $res = self::$default;
      }
      return $res;
    }

    public static function getRootInstance(){
      $res = null;
      if(!isset(self::$root)){
        $res = self::getInstnace();
      }
      else{
        $res = self::$root;
      }
      return $res;
    }

    public static function setDefaultInstance(Settings $settings){
      self::$default = $settings;
    }

    public function specify($areaType = "global",$area = "global"){
      if(!isset($this->$instances[$areaType][$area][$this->dir])){
        $res = Settings::getCached($area,$areaType,$this->dir);
        $res->parent = $this;
        $this->instances[$areaType][$area][$this->dir] = $res;
      }
      else{
        $res = $this->instances[$areaType][$area][$this->dir];
      }
      return $res;
    }

    public function dir($dir,$settings = null){
      if($settings == null){
        $settings = $this;
      }
      if(substr($dir,0,1) == "/"){
        $dir = substr($dir,1);
      }
      if(!isset($this->$instances[$this->areaType][$this->area][$this->dir."/".$dir])){
        $localdir = $dir;
        if(strpos($dir,"/") > -1){
          $localdir = explode("/",$dir);
          $localdir = $localdir[0];
        }
        $res = Settings::getCached($this->area,$this->areaType,$this->dir."/".$localdir);
        $res->parent = $this;
        $this->instances[$areaType][$area][$this->dir."/".$dir] = $res;
        if(strpos($dir,"/") > -1){
          $res = $res->dir(substr($dir,strlen($localdir)));
        }
      }
      else{
        $res = $this->instances[$areaType][$area][$this->dir."/".$dir];
      }
      return $res;
    }

    public function cache(){
      $instances = $this->instances;
      $this->instances = null;
      Cache::setData("settings",$this->area."|".$this->areatype."|".$this->dir."|".self::getRoleID(),$this);
      $this->instances = $instances;
    }

    protected static function getRoleID(){
      if(isset($_SESSION['user'])){
       $role = $_SESSION['user']->role->ID;
      }
      else{
        $role = 3;
      }
      return $role;
    }

    protected static function getCached($area,$areatype,$dir){
      $res = null;
      $role = self::getRoleID();
      if(Cache::contains("settings",$area."|".$areatype."|".$dir."|".$role)){
        $res = Cache::getData("settings",$area."|".$areatype."|".$dir."|".$role);
      }
      else{
        $res = new Settings();
        $res->setAreaType($areatype);
        $res->setArea($area);
        $res->setDir($dir);
      }
     return $res;
    }

    public function __destruct(){
      @$this->cache();
    }

    public function getRows($role){
      $res  = array();
      $area = $GLOBALS['db']->EscapeString($this->area);
      $areatype = $GLOBALS['db']->EscapeString($this->areaType);
      $sql  = "SELECT DISTINCT property, description, type FROM {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areatype."' AND activated = 1";
      $rows = $GLOBALS['db']->ReadRows($sql);
      foreach($rows as $row){
        $property = array();
        $property['name']  = $row->property;
        $property['value'] = $this->get($row->property,$role,false);
        $property['description'] = $row->description;
        $property['type'] = $row->type;
        $res[] = $property;
      }
      return $res;
    }

    public static function forceReload(){
      self::$instances = null;
      self::$default = null;
      Cache::clear("settings");
    }

    public static function getValue($key){
      return self::getInstance()->get($key);
    }

  }
?>